<?php
class QQGroupModel extends BaseModel {
	
	/**
	 *
	 * @var Logger
	 */
	private $_logger;
	/**
	 * <h2>构造函数</h2>
	 * <p>调用父类的构造函数，完成必要的初始化工作</p>
	 */
	public function __construct() {
		parent::__construct ();
		Logger::configure ( ROOT_PATH . 'config/log_config.xml' );
		$this->_logger = Logger::getLogger ( __CLASS__ );
	}
	
	/**
	 * <h2>判断是否存在已经持久化的QQGroup对象，如果存在，则返回持久化的ID</h2>
	 * <p>如果持久化容器（这里是MySQL）中，存在$qqgroup->id或$qqgroup->number的对象，
	 * 则认为已经存在，返回对应的ID，如果不存在检测的对象，则返回false
	 * </p>
	 *
	 * @param CMAP $qqgroup        	
	 * @return int
	 */
	public function isExists(CMAP $qqgroup) {
		if (is_null ( $qqgroup ) || ! is_object ( $qqgroup )) {
			return false;
		}
		$query = 'SELECT id FROM qqgroups WHERE id=:id OR number=:number LIMIT 1';
		$param = array (
				'id' => $qqgroup->id,
				'number' => $qqgroup->number 
		);
		$map [] = array (
				'id',
				'int',
				null 
		);
		$map [] = array (
				'number',
				'string',
				'' 
		);
		
		try {
			$resultSet = $this->_conn->select ( $query, $param, $map );
			if (count ( $resultSet ) > 0) {
				return $resultSet [0] ['id'];
			} else {
				return false;
			}
		} catch ( Exception $e ) {
			$this->_logger->error ( 'QUERY DB failed.' );
			return false;
		}
	}
	
	/**
	 * <h2>储存QQ群记录</h2>
	 * <p>
	 * 保存QQGroup的实体到数据库，并通过参数返回插入数据库的记录对应的Id。如果函数执行失败，则设置错误码，调用者可通过getLastError()获取错误码做进一步处理
	 * </p>
	 *
	 * @param TQqgroup $qqgroup
	 *        	要保存的qqgroup对象
	 * @param int $saveId
	 *        	引用类型，用来返回插入数据库的记录的Id
	 * @return integer 返回错误码，<b> STATUS_SUCCESS
	 *         </b>代表成功，<b>STATUS_FAILED</b>表示失败，具体参考errno.php
	 */
	public function save(CMAP $qqgroup, &$saveId) {
		if (empty ( $qqgroup )) {
			return STATUS_FAILED;
		}
		/*
		 * 针对存在和不存在的记录，分开处理
		 */
		$id = $this->isExists ( $qqgroup );
		if (false != $id) {
			$qqgroup->id = $id;
			$query = 'UPDATE qqgroups SET number=:number, name=:name, master=:master, master_qq=:master_qq, ts_created=:ts_created, verifypwd=:verifypwd, image=:image, hits=:hits, user_id=:user_id, qgcat_id=:qgcat_id, prv_id=:prv_id, city_id=:city_id, dist_id=:dist_id, del_flag=:del_flag, rcm_flag=:rcm_flag, top_flag=:top_flag, ext_flags=:ext_flags, intro=:intro, ext=:ext WHERE id=:id';
		} else {
			$query = 'INSERT INTO qqgroups SET number=:number, name=:name, master=:master, master_qq=:master_qq, ts_created=:ts_created, verifypwd=:verifypwd, image=:image, hits=:hits, user_id=:user_id, qgcat_id=:qgcat_id, prv_id=:prv_id, city_id=:city_id, dist_id=:dist_id, del_flag=:del_flag, rcm_flag=:rcm_flag, top_flag=:top_flag, ext_flags=:ext_flags, intro=:intro, ext=:ext';
		}
		
		$param = array (
				'id' => $qqgroup->id,
				'number' => $qqgroup->number,
				'name' => $qqgroup->name,
				'master' => $qqgroup->master,
				'master_qq' => $qqgroup->master_qq,
				'ts_created' => $qqgroup->ts_created,
				'verifypwd' => $qqgroup->verifypwd,
				'image' => $qqgroup->image,
				'hits' => $qqgroup->hits,
				'user_id' => $qqgroup->user_id,
				'qgcat_id' => $qqgroup->qgcat_id,
				'prv_id' => $qqgroup->prv_id,
				'city_id' => $qqgroup->city_id,
				'dist_id' => $qqgroup->dist_id,
				'del_flag' => $qqgroup->del_flag,
				'rcm_flag' => $qqgroup->rcm_flag,
				'top_flag' => $qqgroup->top_flag,
				'ext_flags' => $qqgroup->ext_flags,
				'intro' => $qqgroup->intro,
				'ext' => $qqgroup->ext 
		);
		
		$cols = array_keys ( $param );
		$map = $this->_filterMap ( $cols );
		try {
			if ($id) {
				$this->_conn->update ( $query, $param, $map );
				$saveId = $id;
			} else {
				$saveId = $this->_conn->insert ( $query, $param, $map );
			}
			return STATUS_SUCCESS;
		} catch ( Exception $e ) {
			$this->_logger->error ( $e->getMessage () );
			return STATUS_FAILED;
		}
	}
	
	/**
	 * <h2>更新指定ID的记录的属性</h2>
	 *
	 * @param CINT $id        	
	 * @param array $profiles        	
	 * @return scalar
	 */
	public function update(CINT $id, array &$profiles) {
		$colSpecs = array_keys ( $profiles );
		$map = $this->_filterMap ( $colSpecs );
		array_walk ( $colSpecs, array (
				$this,
				'_makeColumnsSpec' 
		) );
		$cols = implode ( ', ', $colSpecs );
		$query = 'UPDATE qqgroups SET ' . $cols . ' WHERE id=' . $id->getValue ();
		$this->_logger->debug ( 'UPDATE QQGroup - ' . $query );
		try {
			$this->_conn->update ( $query, $profiles, $map );
		} catch ( Exception $e ) {
			return STATUS_FAILED;
		}
		return STATUS_SUCCESS;
	}
	
	/**
	 * <h2>删除QQ群记录</h2>
	 * <p>支持可变参数，将要删除的记录的id传进去，返回成功删除的记录数，如果删除失败则返回0</p>
	 *
	 * @param
	 *        	int
	 * @return int
	 */
	public function delete($id) {
		$argc = func_num_args ();
		if (argc == 0) {
			return 0;
		}
		$idlist = func_get_args ();
		$idString = implode ( ',', $idlist );
		$query = 'delete from qqgroups where id in (' . $idString . ')';
		$this->_logger->debug ( 'DELETE ## ' . $query );
		$conn = DBHelper::getDB ( false );
		$result = $conn->delete ( $query );
		return $result;
	}
	
	/**
	 * <h2>获取最新的QQ群列表</h2>
	 *
	 * @param int $limit
	 *        	获取的列表限制，默认值10
	 * @param array $cols
	 *        	指定要获取的列，默认值为全部的列
	 * @param int $timestamp
	 *        	指定最远的时间戳，默认不限制
	 * @return CLIST&lt;CMAP&gt;
	 */
	public function getLatest($limit = 10, array &$cols = null, $timestamp = null) {
		$list = new CLIST ();
		
		$selColumns = null;
		if (! empty ( $cols ) && sizeof ( $cols ) > 0) {
			$selColumns = implode ( ',', $cols );
		}
		if ($selColumns == null) {
			$selColumns = 'id, name, number';
		}
		if ($timestamp == null) {
			$query = "select {$selColumns} from qqgroups order by ts_created desc limit {$limit}";
		} else {
			$query = "select {$selColumns} from qqgroups where ts_created>{$timestamp} order by ts_created desc limit {$limit}";
		}
		
		$conn = DBHelper::getDB ( false );
		$resultSet = $conn->select ( $query );
		if (is_array ( $resultSet )) {
			foreach ( $resultSet as $row ) {
				$map = new CMAP ( $row );
				$list->append ( $map );
			}
		}
		return $list;
	}
	
	/**
	 * <h2>获取QQ群记录的列表</h2>
	 *
	 * @param array $condition
	 *        	筛选条件集合
	 *        	@parem array $columns 要获取的属性
	 * @param int $page
	 *        	分页页码
	 * @param
	 *        	int pageSize 页面大小
	 * @param scalar $order
	 *        	排序方式，由常量指定
	 * @return CLIST
	 */
	public function getList(array &$condition, array &$columns, $page = 1, $pageSize = 30, $order = QQGroupModel::ORDER_BY_TS_DESC) {
		$list = new CLIST (); // 存储查询出来的结果
		                      
		// 构造要查询的列
		$colsString = implode ( ', ', $columns );
		if (strlen ( $colsString ) == 0) {
			$colsString = '*'; // 没有指定查询列，则查询出所有列
		}
		
		// 构造Connector需要的参数化字符串
		$colSpecs = array_keys ( $condition ); // 获取参数列表
		$map = $this->_filterMap ( $colSpecs ); // 获取map
		array_walk ( $colSpecs, array (
				$this,
				'_makeColumnsSpec' 
		) );
		$paramQueryString = implode ( ' and ', $colSpecs ); // 合并
		if (strlen ( $paramQueryString ) > 0) {
			$paramQueryString = 'WHERE ' . $paramQueryString;
		}
		
		// 计算排序方式
		$orderString = '';
		switch ($order) {
			case self::ORDER_BY_TS_DESC :
				$orderString = 'ORDER BY ts_created DESC';
				break;
			case self::ORDER_BY_TS_ASC :
				$orderString = 'ORDER BY ts_created ASC';
				break;
		}
		
		// 计算分页
		$pageString = 'LIMIT ' . $pageSize;
		$offset = $page > 1 ? ($page - 1) * $pageSize : 0;
		if ($offset != 0) {
			$pageString .= ',' . $offset;
		}
		
		// 构造最终的SQL
		$query = "SELECT {$colsString} FROM qqgroups {$paramQueryString} {$orderString} {$pageString}";
		try {
			if (count ( $condition ) == 0) {
				$conn = DBHelper::getDB ( false ); // 非参数化
				$resultSet = $conn->select ( $query );
			} else {
				$resultSet = $this->_conn->select ( $query, $condition, $map );
			}
			if (count ( $resultSet ) > 0) {
				foreach ( $resultSet as $row ) {
					$list->append ( new CMAP ( $row ) );
				}
			}
		} catch ( Exception $e ) {
			$this->_logger->error ( 'Get QQGroup List failed.' . $e->getMessage () );
		}
		return $list;
	}
	
	/**
	 * <h2>获取已经持久化的记录总数</h2>
	 * <p>如果函数失败，记录一条错误日志，然后返回0</p>
	 *
	 * @return int
	 */
	public function getTotalCount() {
		$conn = DBHelper::getDB ( false );
		$query = 'SELECT count(id) as cnt FROM qqgroups';
		try {
			$resultSet = $conn->select ( $query );
			return sizeof ( $resultSet ) ? $resultSet [0] ['cnt'] : 0;
		} catch ( Exception $e ) {
			$this->_logger->error ( 'Get total count of QQGroups failed.' . 'error message:' . $e->getMessage () . ' errorcode:' . $e->getCode () );
			return 0;
		}
	}
	
	/**
	 * <h2>根据ID获取一个详细的记录</h2>
	 * <p>如果查询到指定ID的记录，返回该记录的属性的关系映射，否则返回null</p>
	 *
	 * @param int $id
	 *        	要获取详细信息的QQ群的ID
	 *        	@ return CMAP
	 */
	public function getDetailById($id) {
		$query = 'SELECT id, number, name, master, master_qq, ts_created, verifypwd, image, hits, user_id, qgcat_id, prv_id, city_id, dist_id, del_flag, rcm_flag, top_flag, ext_flags, intro FROM qqgroups WHERE id=:id LIMIT 1';
		$param = array (
				'id' => $id 
		);
		$map [] = array (
				'id',
				'int' 
		);
		try {
			$resultSet = $this->_conn->select ( $query, $param, $map );
			if (count ( $resultSet ) > 0) {
				$qqgroup = new CMAP ( $resultSet [0] );
				return $qqgroup;
			} else {
				return null;
			}
		} catch ( Exception $e ) {
			$this->_logger->error ( 'Get QQGroup Detail by id failed. ' . $e->getMessage () . ' in class ' . __CLASS__ . ' at line ' . __LINE__ );
			return null;
		}
	}
	
	/**
	 * <h2>根据QQ群号码获取一个详细记录</h2>
	 * <p>如果查询到指定QQ群号码的记录，返回该记录的属性的关系映射，否则返回null</p>
	 *
	 * @param string $number
	 *        	要获取详细信息的QQ群的号码
	 *        	@ return CMAP
	 */
	public function getDetailByNumber($number) {
		$query = 'SELECT id, number, name, master, master_qq, ts_created, verifypwd, image, hits, user_id, qgcat_id, prv_id, city_id, dist_id, del_flag, rcm_flag, top_flag, ext_flags, intro FROM qqgroups WHERE number=:number LIMIT 1';
		$param = array (
				'number' => $number 
		);
		$map [] = array (
				'number',
				'string' 
		);
		try {
			$resultSet = $this->_conn->select ( $query, $param, $map );
			if (count ( $resultSet ) > 0) {
				$qqgroup = new CMAP ( $resultSet [0] );
				return $qqgroup;
			} else {
				return null;
			}
		} catch ( Exception $e ) {
			$this->_logger->error ( 'Get QQGroup Detail by number failed. ' . $e->getMessage () . ' in class ' . __CLASS__ . ' at line ' . __LINE__ );
			return null;
		}
	}
	
	/**
	 * <h2>将Hit(被查看的次数)增加1</h2>
	 *
	 * @param
	 *        	int id 要增加计数的记录ID
	 * @return void
	 */
	public function incHits($id) {
		$query = 'UPDATE qqgroups SET hits=hits+1 WHERE id=:id';
		$param = array (
				'id' => $id 
		);
		$map [] = array (
				'id',
				'int' 
		);
		try {
			$this->_conn->update ( $query, $param, $map );
		} catch ( Exception $e ) {
			$this->_logger->error ( 'Incerese QQGroup hits failed.' );
		}
	}
	
	/*
	 * 将数组的值凑成适合Connector处理的格式
	 */
	private function _makeColumnsSpec(&$item, $idx) {
		$item .= "=:{$item}";
	}
	
	/**
	 *
	 * @param array $cols        	
	 * @return multitype:Ambigous <multitype:string NULL , multitype:string ,
	 *         multitype:string number >
	 */
	private function _filterMap(array &$cols) {
		$map = array ();
		$arrObj = new ArrayObject ( $cols );
		$iter = $arrObj->getIterator ();
		
		while ( $iter->valid () ) {
			$k = $iter->current ();
			foreach ( $this->_map as $field ) {
				if ($k === $field [0]) {
					$map [] = $field;
				}
			}
			$iter->next ();
		}
		return $map;
	}
	
	//@formatter:off
    private $_map = array (
        /*field			type		default*/
        array ( 'id', 			'int', 		null 	),
        array ( 'number', 		'string' 			), // cannot be empty, so no default value
        array ( 'name',        'string',   ''      ),
        array ( 'master', 		'string', 	'' 		),
        array ( 'master_qq', 	'string', 	'' 		),
        array ( 'ts_created', 	'int', 		null   ),
        array ( 'verifypwd', 	'string', 	'' 		),
        array ( 'image',		'string', 	'' 		),
        array ( 'hits',			'int', 		0 		),
        array ( 'user_id', 		'int', 		null	),
        array ( 'qgcat_id', 	'int', 		null	),
        array ( 'prv_id',		'int', 		null 	),
        array ( 'city_id',		'int', 		null 	),
        array ( 'dist_id',		'int', 		null	),
        array ( 'del_flag', 	'int', 		0 		),
        array ( 'rcm_flag',		'int', 		0 		),
        array ( 'top_flag', 	'int', 		0 		),
        array ( 'ext_flags', 	'int', 		0 		),
        array ( 'intro',		'string', 	'' 		),
        array ( 'ext',			'string', 	null 	)
    );
    // @formatter:on
	
	/**
	 * 查询条件标记
	 *
	 * @var scalar
	 */
	const PAGE_NUMBER = 0x1;
	const PAGE_SIZE = 0x2;
	const CATEGORY_ID = 0x4;
	const PRV_ID = 0x08;
	const DEFAULT_PAGE_SIZE = 30;
	// 排序方式
	const ORDER_BY_TS_ASC = 0;
	const ORDER_BY_TS_DESC = 1;
}